package com.zx.service.Impl;/**
 * Author:JasonZ
 * Data:2023/4/20
 */

import com.alibaba.fastjson.JSON;
import com.zx.context.AccessContext;
import com.zx.dao.OrderDao;
import com.zx.common.ResponseCommon;
import com.zx.common.TableId;
import com.zx.entity.EcommerceOrder;
import com.zx.feign.NotSecuredBalanceClient;
import com.zx.feign.NotSecuredGoodsClient;
import com.zx.feign.SecuredAddressClient;
import com.zx.feign.SecuredGoodsClient;
import com.zx.service.IOrderService;
import com.zx.vo.AddressInfo;
import com.zx.vo.BalanceInfo;
import com.zx.vo.OrderInfo;
import com.zx.vo.SimpleGoodsInfo;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @program: ecommerce-parent
 * @description:
 * @author: JasonZ
 * @create: 2023-04-20 19:42
 **/
@Service
@Slf4j
public class OrderServiceImpl implements IOrderService {

    @Resource
    private OrderDao orderDao;


    /*根据地址id查询地址信息*/
    @Resource
    private SecuredAddressClient addressClient;
    /*根据id查询简易商品信息*/
    @Resource
    private SecuredGoodsClient securedGoodsClient;
    /*扣减余额操作 交给事务回滚 不用熔断*/
    @Resource
    private NotSecuredBalanceClient notSecuredBalanceClient;
    /*根据id和购买数量计算剩余库存*/
    @Resource
    private NotSecuredGoodsClient notSecuredGoodsClient;

    @Override
    @GlobalTransactional
    public TableId createOrder(OrderInfo orderInfo) {
        System.out.println("--" + orderInfo.getUserAddress());
        //1.先根据id获取对应的地址信息
        ResponseCommon<AddressInfo> addressInfoById = addressClient.getAddressInfoById(orderInfo.getUserAddress());
        //订单对应的地址信息
        AddressInfo addressInfo = addressInfoById.getData();
        log.info("addressInfo: [{}]", JSON.toJSONString(addressInfo));
        //判断地址信息是否为空
        if (CollectionUtils.isEmpty(addressInfo.getAddressItems())) {
            //为空则地址异常
            throw new RuntimeException("user's address is not exist");
        }

        //不为空保存相关订单信息
        EcommerceOrder newOrder = orderDao.save(
                new EcommerceOrder(
                        AccessContext.getUserInfo().getId(),
                        orderInfo.getUserAddress(),
                        JSON.toJSONString(orderInfo.getOrderItems())
                )
        );
        log.info("create order success: [{}]", JSON.toJSONString(newOrder));

        //3.扣库存
        Boolean flag = notSecuredGoodsClient.deductGoodsInventory(
                orderInfo.getOrderItems().stream().map(OrderInfo.OrderItem::toDeductGoodsInventory).collect(Collectors.toList())
        ).getData();
        //判断库存是否计算成功(库存量如果不足会抛出异常)
        if (!flag) {
            throw new RuntimeException("deduct goods inventory failed...");
        }
        //4.扣账户余额
        //计算扣钱的总金额
        //先查询购买的商品
        List<Long> goodsId = orderInfo.getOrderItems().stream().map(OrderInfo.OrderItem::getGoodsId).collect(Collectors.toList());
        //再根据查询出来的id得到商品
        List<SimpleGoodsInfo> simpleGoodsInfos = securedGoodsClient.getSimpleGoodsInfos(new TableId(
                goodsId.stream().map(TableId.Id::new).collect(Collectors.toList())
        )).getData();
        //再从查询得到商品进行总价的运算
        Long sum = 0L;
        //4.1传进来查找到的商品转成map
        Map<Long, SimpleGoodsInfo> simpleGoodsInfoMap = simpleGoodsInfos.stream().collect(Collectors.toMap(
                SimpleGoodsInfo::getId,
                Function.identity()
        ));
        ArrayList<String> a = new ArrayList<>();
        //4.2 获得订单的订单项
        List<OrderInfo.OrderItem> orderItems = orderInfo.getOrderItems();
        //遍历orderItems
        for (OrderInfo.OrderItem s : orderItems) {
            log.info("goods price: [{}], count: [{}]", simpleGoodsInfoMap.get(s.getGoodsId()).getPrice(), s.getCount());
            sum += simpleGoodsInfoMap.get(s.getGoodsId()).getPrice() * s.getCount();
        }
        if (sum > 0) {
            //总金额为正数
            log.info("deduct balance : [{}]", sum);
            BalanceInfo balanceInfo = notSecuredBalanceClient.deductBalance(
                    new BalanceInfo(
                            AccessContext.getUserInfo().getId(),
                            sum
                    )
            ).getData();
            if(balanceInfo == null){
                throw new RuntimeException("deduct user balance failed");
            }
            log.info("deduct user balance: [{}]",JSON.toJSONString(balanceInfo));
        }
        return new TableId(
                Collections.singletonList(new TableId.Id(newOrder.getId()))
        );
    }
}
